package io.itit.ecp.admin.provide.action.controller;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.constants.ParamConstants;
import io.itit.ecp.admin.common.enums.IDataRangeEnums;
import io.itit.ecp.admin.provide.action.req.SceneEdificeQueryReq;
import io.itit.ecp.admin.provide.action.req.SceneEdificeReq;
import io.itit.ecp.admin.provide.action.resp.SceneEdificeResp;
import io.itit.ecp.admin.provide.helper.DataRangeHelper;
import io.itit.ecp.admin.provide.renderer.SceneEdificeRenderer;
import io.itit.ecp.admin.server.entity.SceneEdificeEntity;
import io.itit.ecp.admin.server.entity.SceneProjectEntity;
import io.itit.ecp.admin.server.service.ISceneEdificeService;
import io.itit.ecp.admin.server.service.ISceneProjectService;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：楼栋控制类
 * @Date：Create by 2023-11-23 09:55:22
 */
@Api(tags = "楼栋管理")
@RestController
@RequestMapping("/ecp-admin/sceneEdifice")
public class SceneEdificeController {

    @Resource
    private ISceneEdificeService sceneEdificeService;

    @Resource
    private ISceneProjectService sceneProjectService;


    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:sceneEdifice:search")
    public ResultResp<IPage<SceneEdificeResp>> queryPage(@RequestBody @Validated(IQueryPage.class) SceneEdificeQueryReq req) {
        Page<SceneEdificeResp> page = buildQW(req).joinPage(PageUtils.getPage(req, SceneEdificeResp.class), SceneEdificeResp.class);
        return ResultResp.success(page);
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    @RequiresPermissions("ecp-admin:sceneEdifice:search")
    public ResultResp<SceneEdificeResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        return ResultResp.success(ConvertUtils.copy(sceneEdificeService.getById(req.getId()), SceneEdificeResp.class));
    }

    @ApiOperation("列表查询")
    @PostMapping("queryTree")
    public ResultResp<List<Map<String, Object>>> queryList(@RequestBody SceneEdificeQueryReq req) {
        List<SceneProjectEntity> projectList = sceneProjectService.lambdaQuery().orderByDesc(SceneProjectEntity::getCreateTm).list();
        List<SceneEdificeResp> list = buildQW(req).joinList(SceneEdificeResp.class);
        List<Map<String, Object>> result = new ArrayList<>(projectList.size());
        Map<String, List<SceneEdificeResp>> projectMap = list.stream().collect(Collectors.groupingBy(SceneEdificeResp::getSceneProjectId));
        for (SceneProjectEntity item : projectList) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", item.getId());
            m.put("label", item.getProjectName());
            m.put("type", 1);
            m.put("children", projectMap.getOrDefault(item.getId(), Collections.emptyList()).stream().map(edifice -> {
                Map<String, Object> edificeMap = new HashMap<>();
                edificeMap.put("id", edifice.getId());
                edificeMap.put("label", edifice.getEdificeName());
                edificeMap.put("type", 2);
                return edificeMap;
            }).collect(Collectors.toList()));
            result.add(m);
        }
        return ResultResp.success(result);
    }

    /**
     * 组装查询条件
     */
    private static JoinLambdaWrapper<SceneEdificeEntity> buildQW(SceneEdificeQueryReq req) {
        // 如果数据范围权限小于楼栋级别就不能查询楼栋数据
        if (IDataRangeEnums.RangeLevel.getLevel(DataRangeHelper.i().getDataRangeLevel()) > 3) {
            return Joins.of(SceneEdificeEntity.class).last(ParamConstants.LIMIT_ZERO);
        }
        return Joins.of(SceneEdificeEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneEdificeEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), SceneEdificeEntity::getSceneProjectId, req.getSceneProjectId())
                .like(StringUtils.isNotEmpty(req.getEdificeName()), SceneEdificeEntity::getEdificeName, req.getEdificeName())
                .eq(req.getStartNum() != null, SceneEdificeEntity::getStartNum, req.getStartNum())
                .eq(req.getEndNum() != null, SceneEdificeEntity::getEndNum, req.getEndNum())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), SceneEdificeEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), SceneEdificeEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByAsc(SceneEdificeEntity::getEdificeName);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:sceneEdifice:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) SceneEdificeReq req) {
        checkDataExists(req);
        SceneEdificeEntity sceneEdifice = ConvertUtils.convertIgnoreId(req, SceneEdificeEntity.class);
        boolean res = sceneEdificeService.saveEdifice(sceneEdifice, req.getFloorJson());
        return ResultResp.success(res);
    }

    @ApiOperation("查询可设置的最大值")
    @PostMapping("getrange")
    public ResultResp<Map<String, BigDecimal>> getRange(@RequestBody SceneEdificeReq req) {
        SceneProjectEntity projectEntity = sceneProjectService.getById(req.getSceneProjectId());
        BigDecimal projectArea = projectEntity.getFloorArea();
        BigDecimal useArea = sceneEdificeService.lambdaQuery()
                .eq(SceneEdificeEntity::getSceneProjectId, projectEntity.getId())
                .ne(StringUtils.isNotEmpty(req.getId()), SceneEdificeEntity::getId, req.getId())
                .list().stream().map(SceneEdificeEntity::getFloorArea).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal res = projectArea.subtract(ObjectUtil.defaultIfNull(useArea, BigDecimal.ZERO));
        return ResultResp.success(Collections.singletonMap("maxValue", res));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:sceneEdifice:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) SceneEdificeReq req) {
        checkDataExists(req);
        SceneEdificeEntity sceneEdifice = ConvertUtils.copy(req, SceneEdificeEntity.class);
        boolean res = sceneEdificeService.updateEdifice(sceneEdifice, req.getFloorJson());
        return ResultResp.success(res);
    }

    private void checkDataExists(SceneEdificeReq req) {
        Long count = sceneEdificeService.lambdaQuery()
                .eq(SceneEdificeEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(SceneEdificeEntity::getEdificeName, req.getEdificeName())
                .ne(StringUtils.isNotEmpty(req.getId()), SceneEdificeEntity::getId, req.getId())
                .count();
        GrassException.throwEx(count > 0, "楼栋名称已存在！");
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:sceneEdifice:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(sceneEdificeService.removeEdifices(Collections.singletonList(req.getId())));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:sceneEdifice:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(sceneEdificeService.removeEdifices(req.getIds()));
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:sceneEdifice:upload")
    public ResultResp<Integer> upload(@RequestParam("file") MultipartFile file, Boolean ignoreError) {
        return ResultResp.success(ExcelParseManage.i().process(SceneEdificeRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:sceneEdifice:export")
    public void export(@RequestBody @Validated(IExport.class) SceneEdificeQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("SceneEdificeExport", JsonUtil.toJson(buildQW(req).joinList(SceneEdificeResp.class)), response);
    }
}
